package com.naiterui.ehp.bs.pc.modules.sys.service.impl;

import java.util.List;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.base.Preconditions;
import com.naiterui.ehp.bp.support.exception.BaseExceptionCodes;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bs.pc.common.constants.CacheConstants;
import com.naiterui.ehp.bs.pc.common.entity.BaseTree;
import com.naiterui.ehp.bs.pc.common.utils.Constant;
import com.naiterui.ehp.bs.pc.modules.sys.entity.Menu;
import com.naiterui.ehp.bs.pc.modules.sys.entity.User;
import com.naiterui.ehp.bs.pc.modules.sys.mapper.MenuMapper;
import com.naiterui.ehp.bs.pc.modules.sys.service.IMenuService;
import com.naiterui.ehp.bs.pc.modules.sys.service.IUserService;

@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements IMenuService {

    @Autowired
    private IUserService userService;

    @Override
    @Cacheable(value = CacheConstants.MENU_LIST)
    public List<Menu> queryList() {
        QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByAsc("order_num");
        List<Menu> menuList = super.list(queryWrapper);
        return BaseTree.listToTree(menuList).stream().filter(menu -> menu.getParentId() == -1).collect(Collectors.toList());
    }

    @Override
    public List<Menu> queryNotButtonList() {
        List<Menu> menus = this.baseMapper.queryNotButtonList();
        // 添加顶级菜单
        Menu root = new Menu();
        root.setId(-1L);
        root.setName("一级菜单");
        root.setParentId(-2L);
        menus.add(root);
        return BaseTree.listToTree(menus);
    }

    @Override
    public List<Menu> queryNotHiddenList() {
        List<Menu> menus = this.baseMapper.queryHiddenList(0);
        return BaseTree.listToTree(menus).stream().filter(menu -> menu.getParentId() == -1).collect(Collectors.toList());
    }

    @Override
    @Cacheable(value = CacheConstants.USER_MENU_LIST, key = "#userId")
    public List<Menu> getUserMenuList(Long userId) {
        // 系统管理员，拥有最高权限
        User user = this.userService.getById(userId);
        if (user.getRoleIdList().contains(Constant.SUPER_ADMIN)) {
            List<Menu> menus = this.baseMapper.queryNotButtonList();
            menus.addAll(this.baseMapper.queryHiddenList(1));
            return BaseTree.listToTree(menus);
        }
        // 用户菜单列表
        List<Long> menuIdList = this.userService.queryAllMenuId(userId);
        Long[] ids = new Long[menuIdList.size()];
        menuIdList.toArray(ids);
        List<Menu> menus = this.baseMapper.getByIds(ids);
        menus.addAll(this.baseMapper.queryHiddenList(1));
        return BaseTree.listToTree(menus);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {CacheConstants.MENU_LIST, CacheConstants.USER_MENU_LIST, CacheConstants.MENU_ALL, CacheConstants.USER, CacheConstants.PERMISSION_CACHE_PREFIX}, allEntries = true)
    public void delete(Long menuId) throws BusinessException {
        // 判断是否有子菜单或按钮
        List<Menu> menuList = this.baseMapper.queryListParentId(menuId);
        if (menuList.size() > 0) {
            throw new BusinessException(BaseExceptionCodes.FAILED, "请先删除子菜单或按钮");
        }
        // 删除菜单
        super.removeById(menuId);
        // 删除菜单与角色关联
        Menu menu = new Menu();
        menu.setId(menuId);
        super.remove(new QueryWrapper<>(menu));
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {CacheConstants.MENU_LIST, CacheConstants.USER_MENU_LIST, CacheConstants.MENU_ALL, CacheConstants.USER, CacheConstants.PERMISSION_CACHE_PREFIX}, allEntries = true)
    public boolean save(Menu menu) {
        // 数据校验
        this.verifyForm(menu);
        return super.save(menu);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {CacheConstants.MENU_LIST, CacheConstants.USER_MENU_LIST, CacheConstants.MENU_ALL, CacheConstants.USER, CacheConstants.PERMISSION_CACHE_PREFIX}, allEntries = true)
    public boolean updateById(Menu menu) {
        // 数据校验
        Preconditions.checkNotNull(menu.getId(), "菜单ID不能为null");
        this.verifyForm(menu);
        return super.updateById(menu);
    }

    /**
     * 验证参数是否正确
     */
    private void verifyForm(Menu menu) {

        if (StringUtils.isBlank(menu.getName())) {
            throw new IllegalStateException("菜单名称不能为空");
        }

        if (menu.getParentId() == null) {
            throw new IllegalStateException("上级菜单不能为空");
        }

        // 菜单
        if (menu.getType() == Constant.MenuType.MENU.getValue()) {
            if (StringUtils.isBlank(menu.getUrl())) {
                throw new IllegalStateException("菜单URL不能为空");
            }
        }

        // 上级菜单类型
        int parentType = Constant.MenuType.CATALOG.getValue();
        if (menu.getParentId() > 0) {
            Menu parentMenu = this.baseMapper.selectById(menu.getParentId());
            parentType = parentMenu.getType();
        }

        // 目录、菜单
        if (menu.getType() == Constant.MenuType.CATALOG.getValue() || menu.getType() == Constant.MenuType.MENU.getValue()) {
            if (parentType != Constant.MenuType.CATALOG.getValue()) {
                throw new IllegalStateException("上级菜单只能为目录类型");
            }
            return;
        }

        // 按钮
        if (menu.getType() == Constant.MenuType.BUTTON.getValue()) {
            if (parentType != Constant.MenuType.MENU.getValue()) {
                throw new IllegalStateException("上级菜单只能为菜单类型");
            }
        }
        if (menu.getId() != null && menu.getId().equals(menu.getParentId())) {
            throw new IllegalStateException("上级菜单不能选择自己");
        }
    }

}
